load("@bazel_skylib//rules:common_settings.bzl", "string_flag")
load("//tachyon/math/elliptic_curves/bn/generator:build_defs.bzl", "generate_bn_curves")
load("//tachyon/math/elliptic_curves/short_weierstrass/generator:build_defs.bzl", "generate_ec_points")
load(
    "//tachyon/math/finite_fields/generator/ext_field_generator:build_defs.bzl",
    "generate_fp12s",
    "generate_fp2s",
    "generate_fp6s",
)
load(
    "//tachyon/math/finite_fields/generator/prime_field_generator:build_defs.bzl",
    "SMALL_SUBGROUP_ADICITY",
    "SMALL_SUBGROUP_BASE",
    "SUBGROUP_GENERATOR",
    "generate_fft_prime_fields",
    "generate_large_fft_prime_fields",
)

package(default_visibility = ["//visibility:public"])

string_flag(
    name = "fq_" + SUBGROUP_GENERATOR,
    build_setting_default = "3",
)

# Parameters are from https://zips.z.cash/protocol/protocol.pdf#page=97 and https://github.com/arkworks-rs/curves/tree/master/bn254/src/fields
generate_fft_prime_fields(
    name = "fq",
    class_name = "Fq",
    # Hex: 0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47
    modulus = "21888242871839275222246405745257275088696311157297823662689037894645226208583",
    namespace = "tachyon::math::bn254",
    subgroup_generator = ":fq_" + SUBGROUP_GENERATOR,
)

string_flag(
    name = "fr_" + SMALL_SUBGROUP_ADICITY,
    build_setting_default = "2",
)

string_flag(
    name = "fr_" + SMALL_SUBGROUP_BASE,
    build_setting_default = "3",
)

string_flag(
    name = "fr_" + SUBGROUP_GENERATOR,
    build_setting_default = "5",
)

generate_large_fft_prime_fields(
    name = "fr",
    class_name = "Fr",
    # Hex: 0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001
    modulus = "21888242871839275222246405745257275088548364400416034343698204186575808495617",
    namespace = "tachyon::math::bn254",
    small_subgroup_adicity = ":fr_" + SMALL_SUBGROUP_ADICITY,
    small_subgroup_base = ":fr_" + SMALL_SUBGROUP_BASE,
    subgroup_generator = ":fr_" + SUBGROUP_GENERATOR,
)

generate_fp2s(
    name = "fq2",
    base_field = "Fq",
    base_field_hdr = "tachyon/math/elliptic_curves/bn/bn254/fq.h",
    class_name = "Fq2",
    is_packed = False,
    namespace = "tachyon::math::bn254",
    non_residue = ["-1"],
    deps = [":fq"],
)

generate_fp6s(
    name = "fq6",
    base_field = "Fq2",
    base_field_degree = 2,
    base_field_hdr = "tachyon/math/elliptic_curves/bn/bn254/fq2.h",
    class_name = "Fq6",
    is_packed = False,
    mul_by_non_residue_override =
        """    // (c0 + c1 * u) * (9 + u) = (9 * c0 - c1) + (9 * c1 + c0) * u
    BaseField f = v;
    // f = 8 * c0 + 8 * c1 * u
    f.DoubleInPlace().DoubleInPlace().DoubleInPlace();
    // c0 = -c1
    BasePrimeField c0 = BaseField::Config::MulByNonResidue(v.c1());
    // c0 = 8 * c0 - c1
    c0 += f.c0();
    // c0 = 8 * c0 - c1 + c0
    //    = 9 * c0 - c1
    c0 += v.c0();
    // c1 = 8 * c1 + c1 + c0
    //    = 8 * c1 + c0
    BasePrimeField c1 = f.c1() + v.c1() + v.c0();
    return BaseField(std::move(c0), std::move(c1));""",
    namespace = "tachyon::math::bn254",
    non_residue = [
        "9",
        "1",
    ],
    deps = [":fq2"],
)

generate_fp12s(
    name = "fq12",
    base_field = "Fq6",
    base_field_hdr = "tachyon/math/elliptic_curves/bn/bn254/fq6.h",
    class_name = "Fq12",
    is_packed = False,
    namespace = "tachyon::math::bn254",
    non_residue = [
        "0",
        "1",
        "0",
    ],
    deps = [":fq6"],
)

generate_ec_points(
    name = "g1",
    a = ["0"],
    b = ["3"],
    base_field = "Fq",
    base_field_degree = 1,
    base_field_dep = ":fq",
    base_field_hdr = "tachyon/math/elliptic_curves/bn/bn254/fq.h",
    class_name = "G1",
    # Hex: 0x30644e72e131a0295e6dd9e7e0acccb0c28f069fbb966e3de4bd44e5607cfd48
    endomorphism_coefficient = ["21888242871839275220042445260109153167277707414472061641714758635765020556616"],
    gen_gpu = True,
    glv_coeffs = [
        # Hex: 0x6f4d8248eeb859fc8211bbeb7d4f1128
        "-147946756881789319000765030803803410728",
        # Hex: 0x89d3256894d213e3
        "9931322734385697763",
        "-9931322734385697763",
        # Hex: 0x6f4d8248eeb859fd0be4e1541221250b
        "-147946756881789319010696353538189108491",
    ],
    # Hex: 0x30644e72e131a029048b6e193fd84104cc37a73fec2bc5e9b8ca0b2d36636f23
    lambda_ = "21888242871839275217838484774961031246154997185409878258781734729429964517155",
    namespace = "tachyon::math::bn254",
    scalar_field = "Fr",
    scalar_field_dep = ":fr",
    scalar_field_hdr = "tachyon/math/elliptic_curves/bn/bn254/fr.h",
    x = ["1"],
    y = ["2"],
)

generate_ec_points(
    name = "g2",
    a = [
        "0",
        "0",
    ],
    # 3 / (u + 9)
    b = [
        # Hex: 0x2b149d40ceb8aaae81be18991be06ac3b5b4c5e559dbefa33267e6dc24a138e5
        "19485874751759354771024239261021720505790618469301721065564631296452457478373",
        # Hex: 0x9713b03af0fed4cd2cafadeed8fdf4a74fa084e52d1852e4a2bd0685c315d2
        "266929791119991161246907387137283842545076965332900288569378510910307636690",
    ],
    base_field = "Fq2",
    base_field_degree = 2,
    base_field_dep = ":fq2",
    base_field_hdr = "tachyon/math/elliptic_curves/bn/bn254/fq2.h",
    class_name = "G2",
    endomorphism_coefficient = [
        # Hex: 0x30644e72e131a0295e6dd9e7e0acccb0c28f069fbb966e3de4bd44e5607cfd48
        "21888242871839275220042445260109153167277707414472061641714758635765020556616",
        "0",
    ],
    glv_coeffs = [
        # Hex: 0x6f4d8248eeb859fd0be4e1541221250b
        "-147946756881789319010696353538189108491",
        # Hex: 0x89d3256894d213e3
        "-9931322734385697763",
        "9931322734385697763",
        # Hex: 0x6f4d8248eeb859fc8211bbeb7d4f1128
        "-147946756881789319000765030803803410728",
    ],
    # Hex: 0xb3c4d79d41a917585bfc41088d8daaa78b17ea66b99c90dd
    lambda_ = "4407920970296243842393367215006156084916469457145843978461",
    namespace = "tachyon::math::bn254",
    scalar_field = "Fr",
    scalar_field_dep = ":fr",
    scalar_field_hdr = "tachyon/math/elliptic_curves/bn/bn254/fr.h",
    x = [
        # Hex: 0x1800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed
        "10857046999023057135944570762232829481370756359578518086990519993285655852781",
        # Hex: 0x198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c2
        "11559732032986387107991004021392285783925812861821192530917403151452391805634",
    ],
    y = [
        # Hex: 0x12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa
        "8495653923123431417604973247489272438418190587263600148770280649306958101930",
        # Hex: 0x90689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b
        "4082367875863433681332203403145435568316851327593401208105741076214120093531",
    ],
)

generate_bn_curves(
    name = "bn254",
    class_name = "BN254",
    fq12_dep = ":fq12",
    fq12_hdr = "tachyon/math/elliptic_curves/bn/bn254/fq12.h",
    g1_dep = ":g1",
    g1_hdr = "tachyon/math/elliptic_curves/bn/bn254/g1.h",
    g2_dep = ":g2",
    g2_hdr = "tachyon/math/elliptic_curves/bn/bn254/g2.h",
    namespace = "tachyon::math::bn254",
    twist_mul_by_q_x = [
        # Hex: 0x2fb347984f7911f74c0bec3cf559b143b78cc310c2c3330c99e39557176f553d
        "21575463638280843010398324269430826099269044274347216827212613867836435027261",
        # Hex: 0x16c9e55061ebae204ba4cc8bd75a079432ae2a1d0b7c9dce1665d51c640fcba2
        "10307601595873709700152284273816112264069230130616436755625194854815875713954",
    ],
    twist_mul_by_q_y = [
        # Hex: 0x63cf305489af5dcdc5ec698b6e2f9b9dbaae0eda9c95998dc54014671a0135a
        "2821565182194536844548159561693502659359617185244120367078079554186484126554",
        # Hex: 0x7c03cbcac41049a0704b5a7ec796f2b21807dc98fa25bd282d37f632623b0e3
        "3505843767911556378687030309984248845540243509899259641013678093033130930403",
    ],
    twist_type = "D",
    x = "4965661367192848881",
)
